001 /* 002 * Copyright (c) 2005 Stephen J. McConnell 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.metro.tools; 020 021 import java.net.URI; 022 import java.net.URISyntaxException; 023 024 import net.dpml.component.Directive; 025 026 import net.dpml.metro.info.PartReference; 027 import net.dpml.metro.data.ValueDirective; 028 import net.dpml.metro.data.LookupDirective; 029 import net.dpml.metro.data.NullDirective; 030 import net.dpml.metro.data.FeatureDirective; 031 import net.dpml.metro.info.EntryDescriptor; 032 import net.dpml.metro.info.Type; 033 034 import net.dpml.lang.Value; 035 036 import org.apache.tools.ant.BuildException; 037 038 /** 039 * A simple part datatype. 040 * 041 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 042 * @version 1.1.0 043 */ 044 public class EntryDataType extends ValueDataType implements PartReferenceBuilder 045 { 046 private String m_key; 047 private ClassLoader m_classloader; 048 private String m_spec; 049 private int m_feature = -1; 050 private boolean m_validate = true; 051 052 /** 053 * Set the key that this directive qualifies. 054 * @param key the context entry key 055 */ 056 public void setKey( final String key ) 057 { 058 m_key = key; 059 } 060 061 /** 062 * Set the lookup attribute value. 063 * @param spec the service classname 064 */ 065 public void setLookup( final String spec ) 066 { 067 m_spec = spec; 068 } 069 070 /** 071 * Set the validation flag. 072 * @param flag if false entry validation is disabled 073 */ 074 public void setValidate( final boolean flag ) 075 { 076 m_validate = flag; 077 } 078 079 /** 080 * Set the feature that this directive references. 081 * @param feature the component feature 082 */ 083 public void setFeature( String feature ) 084 { 085 if( null != m_spec ) 086 { 087 final String error = 088 "Attributes 'feature' and 'lookup' are mutually exlusive."; 089 throw new BuildException( error ); 090 } 091 try 092 { 093 m_feature = FeatureDirective.getFeatureForName( feature ); 094 } 095 catch( IllegalArgumentException e ) 096 { 097 final String error = e.getMessage(); 098 throw new BuildException( error ); 099 } 100 } 101 102 //--------------------------------------------------------------------- 103 // Builder 104 //--------------------------------------------------------------------- 105 106 /** 107 * Return a uri identitifying the builder. 108 * 109 * @return the builder uri 110 */ 111 public URI getBuilderURI() 112 { 113 return PART_BUILDER_URI; 114 } 115 116 //--------------------------------------------------------------------- 117 // PartReferenceBuilder 118 //--------------------------------------------------------------------- 119 120 /** 121 * Return the key identifying the part that this builder is building. 122 * @return the key 123 */ 124 public String getKey() 125 { 126 if( null == m_key ) 127 { 128 final String error = 129 "Missing 'key' attribute declaration."; 130 throw new ConstructionException( error ); 131 } 132 return m_key; 133 } 134 135 /** 136 * Return the lookup service classname. 137 * @return the classname 138 */ 139 private String getLookupAttribute() 140 { 141 return m_spec; 142 } 143 144 /** 145 * Build a part reference. 146 * @param classloader the classloader to use 147 * @param type the underlying component type 148 * @return the part reference 149 */ 150 public PartReference buildPartReference( ClassLoader classloader, Type type ) 151 { 152 String key = getKey(); 153 if( !m_validate ) 154 { 155 Directive directive = new NullDirective(); 156 return new PartReference( key, directive ); 157 } 158 else 159 { 160 String spec = getLookupAttribute(); 161 if( null != spec ) 162 { 163 Directive directive = new LookupDirective( spec ); 164 return new PartReference( key, directive ); 165 } 166 else if( m_feature > -1 ) 167 { 168 Directive directive = new FeatureDirective( key, m_feature ); 169 return new PartReference( key, directive ); 170 } 171 else 172 { 173 Directive directive = getValueDirective( classloader, type ); 174 return new PartReference( key, directive ); 175 } 176 } 177 } 178 179 /** 180 * Return a urn identitifying the part handler for this builder. 181 * 182 * @return the part handler uri 183 */ 184 public URI getPartHandlerURI() 185 { 186 return PART_HANDLER_URI; 187 } 188 189 //--------------------------------------------------------------------- 190 // implementation 191 //--------------------------------------------------------------------- 192 193 /** 194 * Return the value directive. 195 * @param classloader the classloader to use 196 * @param type the underlying component type 197 * @return the value directive 198 */ 199 public ValueDirective getValueDirective( ClassLoader classloader, Type type ) 200 { 201 String key = getKey(); 202 String classname = getClassname(); 203 if( null != classname ) 204 { 205 try 206 { 207 classloader.loadClass( classname ); 208 } 209 catch( ClassNotFoundException e ) 210 { 211 final String error = 212 "Entry directive overriding class [" 213 + classname 214 + "] is unknown."; 215 throw new BuildException( error, e ); 216 } 217 } 218 219 String method = getMethodName(); 220 221 if( null != type ) 222 { 223 EntryDescriptor entry = type.getContextDescriptor().getEntryDescriptor( key ); 224 if( null == entry ) 225 { 226 final String error = 227 "The value key [" 228 + key 229 + "] is unknown relative to the component type [" 230 + type.getInfo().getClassname() 231 + "]."; 232 throw new ConstructionException( error ); 233 } 234 else if( null == classname ) 235 { 236 classname = entry.getClassname(); 237 } 238 } 239 240 if( null == classname ) 241 { 242 final String error = 243 "Missing 'class' attribute for entry key [" 244 + key 245 + "]."; 246 throw new ConstructionException( error ); 247 } 248 249 String value = getValue(); 250 if( null != value ) 251 { 252 return new ValueDirective( classname, method, value ); 253 } 254 else 255 { 256 ValueBuilder[] params = getValueBuilders(); 257 Value[] values = new Value[ params.length ]; 258 for( int i=0; i<params.length; i++ ) 259 { 260 ValueBuilder p = params[i]; 261 values[i] = p.buildValue( classloader ); 262 } 263 return new ValueDirective( classname, method, values ); 264 } 265 } 266 267 //--------------------------------------------------------------------- 268 // static utilities 269 //--------------------------------------------------------------------- 270 271 private static final URI PART_HANDLER_URI = setupURI( "artifact:part:dpml/metro/dpml-metro-runtime#1.0.1" ); 272 private static final URI PART_BUILDER_URI = setupURI( "artifact:part:dpml/metro/dpml-metro-tools#1.1.0" ); 273 274 /** 275 * Utility function top create a static uri. 276 * @param spec the uri spec 277 * @return the uri value 278 */ 279 protected static URI setupURI( String spec ) 280 { 281 try 282 { 283 return new URI( spec ); 284 } 285 catch( URISyntaxException ioe ) 286 { 287 return null; 288 } 289 } 290 } 291